// ==================================================================================
// Shared Genomics Project MPI Codebase
// Version 1.0 30/04/2010
//
// (c) 2010 University of Manchester all rights reserved
//
// This file is distributed under the GNU General Public License, Version 2.  
// Please see the file COPYING.txt for more details
// ==================================================================================

/*! 
\file
\brief Main body of BINARY_PED
*/
/*! 
\defgroup	binary_ped BINARY_PED - Binary encoding of Genomic Data-set
\ingroup    mpi_stats
\brief		BINARY_PED - Binary encoding of Genomic Data-set
\details
<p>
Binary PED takes a text PLINK-compatible genomic data-set (PED File + MAP File)
and converts the data-set to a binary format.<br>
PLINK does do this already but NIBHI wanted more control 
over the program outputs and so BINARY_PED was written to do a similar job.<br>
Binary encoding of input data simplifies the task of sub-dividing calculation data across the cores of the 
NIBHI cluster.</p>

<p>A PLINK text-map file (suffix = map) is written to a binary map file (suffix = \ref SUFFIX_BMAP_FILE).<br>
A PLINK text-PED file is written to a SNP-major binary pedigree file (suffix = \ref SUFFIX_BPED_FILE).
</p>

<p>BINARY_PED calculates the person-missingness (MIND) for each %individual in a genomic data-set
and provides summary statistics about about the missingness rates for people and for SNPs.
</p>
<p>If successful BINARY_PED returns with an exitcode of 0, if it encountered an error the programs returns 
with an exit code of -1.</p>

<p>BINARY_PED is a single-core program.</p>

<h2>OPTIONS</H2>

<table class=options border=0>
<tr><th class=param_header colspan=1>PARAMETER</th>
<th class=param_header colspan=3>DESCRIPTION</th></tr>

<tr><td class=param_name colspan=1>--id STRING</td>
<td class=param_desc colspan=3>Unique identifer for a cluster job (also sets output file stem).</td></tr>

<tr><td class=param_name colspan=1>--map FILE</td>
<td class=param_desc colspan=3>Path to a text MAP file (PLINK-compatible, SNP list).</td></tr>

<tr><td class=param_name colspan=1>--ped FILE</td>
<td class=param_desc colspan=3>Path to a SNP-major text pedigree file (PLINK-compatible, Allelic Data).</td></tr>

<tr><td class=param_name colspan=1>--rdir PATH</td>
<td class=param_desc colspan=3>Path to remote working directory on central file system.</td></tr>

<tr><td class=param_name colspan=1>--ldir PATH</td>
<td class=param_desc colspan=3>Path to local working directory on each core of the cluster.</td></tr>
</table>
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "SMG_All.h"

/*!
\brief Command-line options of BINARY_PED
*/
struct option long_options[] = {
	{ "map", required_argument, NULL, 'm' }, // Path to the map file.
	{ "ped", required_argument, NULL, 'p' }, // Path to PED File.
	{ "id", required_argument, NULL, 'i' }, // Run ID
	{ "ldir", required_argument, NULL, 'd'}, // Output direct
	{ "rdir", required_argument, NULL, 'R'}, // Remote Output direct
	{ 0,    0,    0,    0   } 
};

#define NREQUIRED_ARGS 5

/*!
\brief Main body of the BINARY_PED program
\ingroup binary_ped
*/
int binary_ped_main(int argc, char *argv[]) {
	char ch;
	struct selected_options ops;
	struct mapfile map;
	struct chromosomes chromos;
	struct pedfile ped;
	int nRequiredArgs = NREQUIRED_ARGS;
	time_t now = time(NULL);
	BOOL jobDone = FALSE, hasReadMap = FALSE, hasReadPed = FALSE;
	BOOL hasCreatedMissingnessFile = FALSE, hasCreatedFoundersFile = FALSE, hasCreatedBmapFile = FALSE, hasCreatedBpedFile = FALSE;
	int myrank, numprocs, result;

	// Initialise MPI environment, get size and rank.
	if ((result = MPI_Init(&argc,&argv)) != MPI_SUCCESS) 
		mpi_error(result, "Initialisation");
	if ((result = MPI_Comm_size(MPI_COMM_WORLD,&numprocs)) != MPI_SUCCESS)
		mpi_error(result, "Number of processors");
	if ((result = MPI_Comm_rank(MPI_COMM_WORLD,&myrank)) != MPI_SUCCESS)
		mpi_error(result, "Processor number");

	// Must be a single core application.
	if (numprocs != 1) {
		MPI_Finalize();
		return -1;
	}

	init_genrand((unsigned long) now);
	options_init(&ops);
	chromosomes_init(&chromos);
	mapfile_init(&map);
	pedfile_init(&ped);
	
	*ops.rdir = *ops.ldir = *ops.szRunId = '\0'; 
	ops.verbose = FALSE;
	
	while ((ch = (char) getopt_long(argc, argv, "m:v:p:f:i:", long_options, NULL)) != -1) {
		switch (ch) {
			case 'i':
				strcpy(ops.szRunId, optarg);
				nRequiredArgs--;
				break;
			case 'm':
				strcpy(ops.szMapFileName, optarg);
				nRequiredArgs--;
				break;
			case 'd':
				strcpy(ops.ldir, optarg);
				nRequiredArgs--;
				break;
			case 'p':
				strcpy(ops.szPedFileName, optarg);
				nRequiredArgs--;
				break;
			case 'R': 
				strcpy(ops.rdir, optarg);
				nRequiredArgs--;
				break;
			default:
				break;
		}
	}

	// If not all required supplied, stop and moan.
	if (nRequiredArgs != 0) {
		MPI_Finalize();
		return -1;
	}

	chromosomes_define_human(&chromos);

	hasReadMap = mapfile_copy_and_read(&map, &ops, &chromos, myrank) ? TRUE : FALSE;
	if (hasReadMap) hasReadPed = pedfile_copy_and_read(&ped, &map, &ops, myrank) ? TRUE : FALSE;
	if (hasReadPed && hasReadMap) hasCreatedMissingnessFile = missingnessfile_create_and_copy(&map, &ped, &ops, &chromos, myrank) ? TRUE : FALSE;
	if (hasCreatedMissingnessFile) hasCreatedFoundersFile = foundersfile_create_and_copy(&ped, &ops, myrank) ? TRUE : FALSE;
	if (hasCreatedMissingnessFile && hasCreatedFoundersFile) hasCreatedBmapFile = bmapfile_create_and_copy(&map, &chromos, &ops, myrank) ? TRUE : FALSE;
	if (hasCreatedMissingnessFile && hasCreatedFoundersFile && hasCreatedBmapFile) hasCreatedBpedFile = bpedfile_create_and_copy(&ops, &map, myrank) ? TRUE : FALSE;
	
	if (hasCreatedMissingnessFile && hasCreatedFoundersFile && hasCreatedBmapFile && hasCreatedBpedFile) {
		bpedfile_write_summary_and_copy(&ops, &map);
		jobDone = TRUE;
	}

	// Free-up the dynamic memory.
	chromosomes_free_attributes(&chromos);
	mapfile_free_attributes(&map);
	pedfile_free_attributes(&ped);

	MPI_Finalize();
	
	if (jobDone) return 0;
	else return -1;
}

int main(int argc, char *argv[]) {
	return binary_ped_main(argc, argv);
}